package cc.rboot._core.helper;

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import cc.rboot._core.util.ListUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

public class CombineHelper {

    /**
     * 合并两个对象，列表中的值按照匹配方法进行匹配
     *
     * @param targetList 目标对象
     * @param srcList    来源对象
     * @param tFunction  匹配方法
     */
    public static <T, R> void combine(List<T> targetList, List<T> srcList, SFunction<T, R> tFunction) {
        CombineHelper.combine(targetList, srcList, tFunction, tFunction);
    }

    /**
     * 并两个对象，列表中的值按照匹配方法进行匹配
     *
     * @param targetList 目标对象
     * @param srcList    来源对象
     * @param tFunction  目的对象匹配方法
     * @param sFunction  来源对象匹配方法
     * @param <T>        目标对象类型
     * @param <S>        来源对象类型
     * @param <R>        匹配方法的返回值类型
     */
    public static <T, S, R> void combine(List<T> targetList, List<S> srcList, SFunction<T, R> tFunction, SFunction<S, R> sFunction) {
        CombineHelper.combine(targetList, srcList, tFunction, sFunction, CombineHelper::combine);
    }

    /**
     * 并两个对象，列表中的值按照匹配方法进行匹配
     *
     * @param targetList 目标对象
     * @param srcList    来源对象
     * @param tFunction  目的对象匹配方法
     * @param sFunction  来源对象匹配方法
     * @param action     发现匹配后执行的操作
     * @param <T>        目标对象类型
     * @param <S>        来源对象类型
     * @param <R>        匹配方法的返回值类型
     */
    public static <T, S, R> void combine(List<T> targetList, List<S> srcList, SFunction<T, R> tFunction, SFunction<S, R> sFunction, BiConsumer<T, S> action) {
        for (T t : targetList) {
            for(S s : srcList) {
                final R targetR = tFunction.apply(t);
                final R srcR = sFunction.apply(s);
                if (targetR == null || srcR == null) {
                    continue;
                }
                if (targetR.equals(srcR)) {
                    action.accept(t, s);
                }
            }
        }
    }

    /**
     * 强制合并两个对象
     * 只要来源对象的字段有值，则强制覆盖目标对象的字段
     *
     * @param target 目标对象
     * @param src    来源对象
     * @param <T>    目标对象类型
     * @param <S>    来源对象类型
     */
    public static <T, S> void combine(T target, S src) {
        for (Field field : ClassHelper.getAllFieldList(src.getClass())) {
            CombineHelper.combine(target, src, field);
        }
    }

    /**
     * 强制合并两个对象的指定字段
     * 只要来源对象的字段有值，则强制覆盖目标对象的字段
     *
     * @param target 目标对象
     * @param src    来源对象
     * @param field  合并的字段
     * @param <T>    目标对象类型
     * @param <S>    来源对象类型
     */
    public static <T, S> void combine(T target, S src, Field field) {
        field.setAccessible(true);
        try {
            Object srcFieldValue = field.get(src);
            if (field.getType().isAssignableFrom(List.class)) {
                Object targetFieldValue = field.get(target);
                if (targetFieldValue == null) {
                    field.set(target, srcFieldValue);
                } else {
                    List targetFieldList = (List) targetFieldValue;
                    if (srcFieldValue != null) {
                        List srcFieldList = (List) srcFieldValue;
                        targetFieldList.addAll(srcFieldList);
                    }
                }
            } else if (srcFieldValue != null) {
                field.set(target, srcFieldValue);
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException("combine err", e);
        }

    }

}
